/*
 * CPaperDoll.java
 *
 * Copyright (c) 2009 Giles Millward (Manigra). All rights reserved.
 *
 * This file is part of JRogueDPS.
 *
 * JRogueDPS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JRogueDPS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with JRogueDPS.  If not, see <http://www.gnu.org/licenses/>.
 */

package paperdoll;

import geardatabase.CDatabase;
import geardatabase.CGemType.GemType;
import geardatabase.CItem;
import geardatabase.CQualityFilter;
import geardatabase.CStats;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JTable;
import jroguedps.CGlobal;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import paperdoll.CDollSlotType.DollSlotType;
import utility.CUtility;

/**
 *
 * @author Mani
 */
public class CPaperDoll {

    final int c_cellY[] = {6, 4, 5, 5, 5, 6, 6, 6, 5, 5, 5, 5, 1, 1, 6, 6, 4};
    ArrayList<CDollSlot> m_dollSlotRenderMap = new ArrayList<CDollSlot>();
    ArrayList<CDollSlot> m_dollSlot = new ArrayList<CDollSlot>();
    public CQualityFilter m_gemQualityFilter = new CQualityFilter(true, true, true, true, true);
    public CQualityFilter m_itemQualityFilter = new CQualityFilter(true, true, true, true, true);
    JTable m_paperDollTable;
    ArrayList<String> m_professions = new ArrayList<String>();
    String m_race = "Undead";
    CStats m_racialStats = new CStats();


    public void defaultSlots()
    {

        int l_offset = 0;
        int l_slotNo = 0;

        // Setup some maps for the spreadsheet object
        m_dollSlot.clear();
        m_dollSlot.add(new CDollSlot("Head", DollSlotType.HEAD, l_offset, true));
        l_offset += addOffset(getSlot(DollSlotType.HEAD), c_cellY[l_slotNo++]);
        m_dollSlot.add(new CDollSlot("Neck", DollSlotType.NECK, l_offset, false));
        l_offset += addOffset(getSlot(DollSlotType.NECK), c_cellY[l_slotNo++]);
        m_dollSlot.add(new CDollSlot("Shoulders", DollSlotType.SHOULDERS, l_offset, true));
        l_offset += addOffset(getSlot(DollSlotType.SHOULDERS), c_cellY[l_slotNo++]);
        m_dollSlot.add(new CDollSlot("Back", DollSlotType.BACK, l_offset, true));
        l_offset += addOffset(getSlot(DollSlotType.BACK), c_cellY[l_slotNo++]);
        m_dollSlot.add(new CDollSlot("Chest", DollSlotType.CHEST, l_offset, true));
        l_offset += addOffset(getSlot(DollSlotType.CHEST), c_cellY[l_slotNo++]);
        m_dollSlot.add(new CDollSlot("Wrist", DollSlotType.WRIST, l_offset, true));
        l_offset += addOffset(getSlot(DollSlotType.WRIST), c_cellY[l_slotNo++]);
        m_dollSlot.add(new CDollSlot("Hands", DollSlotType.HANDS, l_offset, true));
        l_offset += addOffset(getSlot(DollSlotType.HANDS), c_cellY[l_slotNo++]);
        m_dollSlot.add(new CDollSlot("Waist", DollSlotType.WAIST, l_offset, true));
        l_offset += addOffset(getSlot(DollSlotType.WAIST), c_cellY[l_slotNo++]);
        m_dollSlot.add(new CDollSlot("Legs", DollSlotType.LEGS, l_offset, true));
        l_offset += addOffset(getSlot(DollSlotType.LEGS), c_cellY[l_slotNo++]);
        m_dollSlot.add(new CDollSlot("Feet", DollSlotType.FEET, l_offset, true));
        l_offset += addOffset(getSlot(DollSlotType.FEET), c_cellY[l_slotNo++]);
        m_dollSlot.add(new CDollSlot("Finger", DollSlotType.FINGER1, l_offset, true));
        l_offset += addOffset(getSlot(DollSlotType.FINGER1), c_cellY[l_slotNo++]);
        m_dollSlot.add(new CDollSlot("Finger", DollSlotType.FINGER2, l_offset, true));
        l_offset += addOffset(getSlot(DollSlotType.FINGER2), c_cellY[l_slotNo++]);
        m_dollSlot.add(new CDollSlot("Trinket", DollSlotType.TRINKET1, l_offset, false));
        l_offset += addOffset(getSlot(DollSlotType.TRINKET1), c_cellY[l_slotNo++]);
        m_dollSlot.add(new CDollSlot("Trinket", DollSlotType.TRINKET2, l_offset, false));
        l_offset += addOffset(getSlot(DollSlotType.TRINKET2), c_cellY[l_slotNo++]);
        m_dollSlot.add(new CDollSlot("Main Hand", DollSlotType.MAINHAND, l_offset, true));
        l_offset += addOffset(getSlot(DollSlotType.MAINHAND), c_cellY[l_slotNo++]);
        m_dollSlot.add(new CDollSlot("Off Hand", DollSlotType.OFFHAND, l_offset, true));
        l_offset += addOffset(getSlot(DollSlotType.OFFHAND), c_cellY[l_slotNo++]);
        m_dollSlot.add(new CDollSlot("Ranged", DollSlotType.RANGED, l_offset, false));
        l_offset += addOffset(getSlot(DollSlotType.RANGED), c_cellY[l_slotNo++]);
    }

    public void setTableLink(JTable p_tableLink)
    {
        m_paperDollTable = p_tableLink;
    }

    private int addOffset(CDollSlot p_dollSlot, int p_numberOfRows)
    {
        for (int i = 0; i < p_numberOfRows; i++)
        {
            m_dollSlotRenderMap.add(p_dollSlot);
        }

        return p_numberOfRows;
    }

    public void setItem(CItem p_item, DollSlotType p_slotType)
    {
        CDollSlot l_dollType = getSlot(p_slotType);
        l_dollType.setItem(p_item);
        CDollTableModel l_tblModel = (CDollTableModel) m_paperDollTable.getModel();
        l_tblModel.fireTableStructureChanged();
        CGlobal.g_rootFrame.setStats();
    }

    public void setGem(CItem p_item, DollSlotType p_slotType, int p_index)
    {
        CDollSlot l_dollType = getSlot(p_slotType);
        l_dollType.setGem(p_item, p_index);
        CDollTableModel l_tblModel = (CDollTableModel) m_paperDollTable.getModel();
        l_tblModel.fireTableStructureChanged();
        CGlobal.g_rootFrame.setStats();
    }

    public void setEnchant(CItem p_item, DollSlotType p_slotType)
    {
        CDollSlot l_dollType = this.getSlot(p_slotType);
        l_dollType.setEnchant(p_item);
        CDollTableModel l_tblModel = (CDollTableModel) m_paperDollTable.getModel();
        l_tblModel.fireTableStructureChanged();
        CGlobal.g_rootFrame.setStats();
    }

    public void setPoison(CItem p_item, DollSlotType p_slotType)
    {
        CDollSlot l_dollType = this.getSlot(p_slotType);
        l_dollType.setPoison(p_item);
        CDollTableModel l_tblModel = (CDollTableModel) m_paperDollTable.getModel();
        l_tblModel.fireTableStructureChanged();
        CGlobal.g_rootFrame.setStats();
    }

    public void setBSGem(CItem p_item, DollSlotType p_slotType)
    {
        CDollSlot l_dollType = this.getSlot(p_slotType);
        l_dollType.setBSGem(p_item);
        CDollTableModel l_tblModel = (CDollTableModel) m_paperDollTable.getModel();
        l_tblModel.fireTableStructureChanged();
        CGlobal.g_rootFrame.setStats();
    }

    public void setBBGem(CItem p_item, DollSlotType p_slotType)
    {
        CDollSlot l_dollType = this.getSlot(p_slotType);
        l_dollType.setBBGem(p_item);
        CDollTableModel l_tblModel = (CDollTableModel) m_paperDollTable.getModel();
        l_tblModel.fireTableStructureChanged();
        CGlobal.g_rootFrame.setStats();
    }

    public void setRace(String p_string)
    {
        CGlobal.g_rootFrame.raceComboBox.setSelectedItem(p_string);
        m_race = p_string;
        if (m_race.equals("Blood Elf")) {
            m_racialStats = new CStats("agility=191, strength=110, stamina=103, attackPower=140");
        } else if (m_race.equals("Dwarf")) {
            m_racialStats = new CStats("agility=185, strength=115, stamina=108, attackPower=140");
        } else if (m_race.equals("Gnome")) {
            m_racialStats = new CStats("agility=192, strength=108, stamina=104, attackPower=140");
        } else if (m_race.equals("Human")) {
            m_racialStats = new CStats("agility=189, strength=113, stamina=105, attackPower=140");
        } else if (m_race.equals("Night Elf")) {
            m_racialStats = new CStats("agility=194, strength=110, stamina=104, attackPower=140");
        } else if (m_race.equals("Orc")) {
            m_racialStats = new CStats("agility=186, strength=116, stamina=107, attackPower=140");
        } else if (m_race.equals("Troll")) {
            m_racialStats = new CStats("agility=191, strength=114, stamina=106, attackPower=140");
        } else if (m_race.equals("Undead")) {
            m_racialStats = new CStats("agility=187, strength=112, stamina=106, attackPower=140");
        }
        CGlobal.g_rootFrame.setStats();
    }

    public int getTotalGems(GemType p_gemType)
    {
        int l_totalGems = 0;
        for (int i = 0; i < m_dollSlot.size(); i++)
        {
            l_totalGems += m_dollSlot.get(i).getTotalGems(p_gemType);
        }

        return l_totalGems;
    }

    public void clearItems()
    {
        for (int i = 0; i < m_dollSlot.size(); i++)
        {
            CDollSlot l_slot = m_dollSlot.get(i);
            CItem l_nullItem = CGlobal.g_database.getItem("0");
            l_slot.setItem(l_nullItem);
            l_slot.setEnchant(l_nullItem);
            l_slot.setPoison(l_nullItem);
            l_slot.setBSGem(l_nullItem);
        }

        CDollTableModel l_tblModel = (CDollTableModel) m_paperDollTable.getModel();
        l_tblModel.fireTableStructureChanged();
    }
    
    public void clearProfessions()
    {
        this.m_professions.clear();
        this.m_professions.add("None");
        this.m_professions.add("None");
        CGlobal.g_rootFrame.professionAComboBox.setSelectedItem("None");
        CGlobal.g_rootFrame.professionBComboBox.setSelectedItem("None");
    }



    public void setProfession(String p_profession, int p_index, boolean p_updateComboBox)
    {
        if (p_index == 0)
        {
            this.m_professions.set(p_index, p_profession);
            if (p_updateComboBox)
            {
                CGlobal.g_rootFrame.professionAComboBox.setSelectedItem(p_profession);
            }
        }
        else
        {
            this.m_professions.set(p_index, p_profession);
            if (p_updateComboBox)
            {
                CGlobal.g_rootFrame.professionBComboBox.setSelectedItem(p_profession);
            }
        }

        CGlobal.g_rootFrame.setStats();
    }


    
    public CDollSlot getSlot(DollSlotType p_slotType)
    {
        for (int i = 0; i < m_dollSlot.size(); i++)
        {
            if (m_dollSlot.get(i).m_slotType == p_slotType)
            {
                return m_dollSlot.get(i);
            }
        }
        
        return null;
    }

    public boolean isMetaGemBroken()
    {
        CDollSlot l_slot = this.getSlot(DollSlotType.HEAD);
        if (l_slot.getItem().getNumberOfSockets() == 0)
        {
            // No meta gem anyway
            return true;
        }

        if (l_slot.m_gemList.get(0).getGemType() != GemType.META)
        {
            // No meta gem in there
            return true;
        }

        int l_red = this.getTotalGems(GemType.RED);
        int l_blue = this.getTotalGems(GemType.BLUE);
        int l_yellow = this.getTotalGems(GemType.YELLOW);

        if (l_red < l_slot.m_meta_red_required ||
            l_blue < l_slot.m_meta_blue_required ||
            l_yellow < l_slot.m_meta_yellow_required)
        {
            return true;
        }

        // Meta gem is okay
        return false;
    }

    public boolean isItemEquipped(int p_itemId)
    {
        for (int i = 0; i < m_dollSlot.size(); i++)
        {
            if (m_dollSlot.get(i).getItem().getId() == p_itemId)
            {
                return true;
            }
        }

        return false;
    }
    
    public CStats getTotalStats()
    {
        // Calculate total stats
        CStats l_totalStats = new CStats();
        // Racials first
        l_totalStats.add(this.m_racialStats);
        // Add profession stats
        l_totalStats.add(getProfessionStats());

        for (int i = 0; i < m_dollSlot.size(); i++)
        {
            CDollSlot l_slot = m_dollSlot.get(i);
            l_totalStats.add(l_slot.m_itemId.getItemStats());
            if (l_slot.socketBonus())
            {
                l_totalStats.add(l_slot.m_itemId.getItemBonusStats());
            }
            
            for(int j = 0; j < l_slot.m_gemList.size();j++)
            {
                if (l_slot.m_gemList.get(j).getGemType() == GemType.META)
                {
                    if (this.isMetaGemBroken())
                    {
                        // Dont add meta gem stats if meta gem is broken
                        continue;
                    }
                }
                
                l_totalStats.add(l_slot.m_gemList.get(j).getTotalStats());
            }

            if (l_slot.m_blacksmithGem != null)
            {
                l_totalStats.add(l_slot.m_blacksmithGem.getTotalStats());
            }
            
            if (l_slot.m_enchantId != null)
            {
                l_totalStats.add(l_slot.m_enchantId.getTotalStats());
            }

            if (l_slot.m_beltBuckleGem != null)
            {
                l_totalStats.add(l_slot.m_beltBuckleGem.getTotalStats());
            }

        }

        if (CGlobal.g_rootFrame.statsBoostCheckBox.isSelected())
        {
            l_totalStats.add(CGlobal.g_rootFrame.m_boostStats);
        }

        return l_totalStats;
    }

    public CStats getProfessionStats()
    {
        CStats l_stats = new CStats();
        for (int i = 0; i < m_professions.size(); i++)
        {
            String l_profession = m_professions.get(i);
            if (l_profession.equals("Mining"))
            {
                l_stats.addStamina(50);
            } else if (l_profession.equals("Skinning"))
            {
                l_stats.addCritRating(25);
            }
        }

        return l_stats;
    }

    public CStats getRacialStats()
    {
        return this.m_racialStats;
    }

    public void refreshTable()
    {
        CDollTableModel l_tblModel = (CDollTableModel) m_paperDollTable.getModel();
        l_tblModel.fireTableStructureChanged();
        CGlobal.g_rootFrame.setStats();
    }

    public void renderCell(CDollRenderer p_renderer, int p_x, int p_y)
    {
        // Need to map coords to slot
        m_dollSlotRenderMap.get(p_y).renderCell(p_renderer, p_x, p_y);
    }

    public void itemChooser(int y)
    {
        m_dollSlotRenderMap.get(y).itemChooser(y);
    }

    public void save()
    {
        String l_string = CUtility.openXMLFileSaveDialog("paperdolls", "Set a filename for this paperdoll");
        if (l_string == null)
        {
            return;
        }

        this.save(l_string);
    }

    public void save(String p_fileName) {
        Document doc = DocumentFactory.getInstance().createDocument();
        Element root = doc.addElement("root");
        this.addXMLData(root);

        if (!p_fileName.endsWith(".xml"))
        {
            p_fileName = p_fileName + ".xml";
        }
        
        FileOutputStream fos;
        try {
            fos = new FileOutputStream(p_fileName);
            OutputFormat format = OutputFormat.createPrettyPrint();
            XMLWriter writer;
            try {
                writer = new XMLWriter(fos, format);
                try {
                    writer.write(doc);
                    writer.flush();
                    writer.close();
                } catch (IOException ex) {
                    Logger.getLogger(CDatabase.class.getName()).log(Level.SEVERE, null, ex);
                }

            } catch (UnsupportedEncodingException ex) {
                Logger.getLogger(CDatabase.class.getName()).log(Level.SEVERE, null, ex);
            }

        } catch (FileNotFoundException ex) {
            Logger.getLogger(CDatabase.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void addXMLData(Element p_root)
    {
        Element l_paperDoll = p_root.addElement("paperdoll").
                addAttribute("race", m_race).
                addAttribute("professiona", this.m_professions.get(0)).
                addAttribute("professionb", this.m_professions.get(1));
        Element l_slots = l_paperDoll.addElement("slots");
        for (int i = 0; i < m_dollSlot.size(); i++)
        {
            CDollSlot l_slot = m_dollSlot.get(i);
            l_slot.addXMLData(l_slots);
        }   
    }

    public void read()
    {
        String l_string = CUtility.openXMLFileOpenDialog("paperdolls", "Choose a Paperdoll data file");
        if (l_string == null)
        {
            return;
        }

        this.read(l_string);
    }

    public void read(String l_fileName)
    {
        System.out.println("File String " + l_fileName);

        File l_xml = new File(l_fileName);

        SAXReader l_reader = new SAXReader();
        Document l_doc;
        try {
            l_doc = l_reader.read(l_xml);
            Element l_element = (Element) l_doc.selectSingleNode( "//root/paperdoll" );
            this.parseXMLElement(l_element);
        } catch (DocumentException ex) {
            Logger.getLogger(CPaperDoll.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void parseXMLElement(Element p_element)
    {
        this.setRace(p_element.attributeValue("race"));
        this.setProfession(p_element.attributeValue("professiona"), 0, true);
        this.setProfession(p_element.attributeValue("professionb"), 1, true);


        List l_list = p_element.selectNodes("//root/paperdoll/slots/slot");
        for (Iterator l_iter = l_list.iterator(); l_iter.hasNext(); ) {
                Element l_element = (Element) l_iter.next();
                String l_slotId = l_element.attributeValue("slottype");
                this.getSlot(DollSlotType.valueOf(l_slotId)).parseXMLElement(l_element);
         }
    }
}
